﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;

namespace Nauka.engine
{
    class Parser
    {
        private static int getMonth(string month_str)
        {
            int month_int;
            switch (month_str)
            {
                case "January":
                    month_int = 1;
                    break;
                case "February":
                    month_int = 2;
                    break;
                case "March":
                    month_int = 3;
                    break;
                case "April":
                    month_int = 4;
                    break;
                case "May":
                    month_int = 5;
                    break;
                case "June":
                    month_int = 6;
                    break;
                case "July":
                    month_int = 7;
                    break;
                case "August":
                    month_int = 8;
                    break;
                case "September":
                    month_int = 9;
                    break;
                case "October":
                    month_int = 10;
                    break;
                case "November":
                    month_int = 11;
                    break;
                default:
                    month_int = 12;
                    break;
            }

            return month_int;
        }

        public ArrayList parse(string file_name)
        {
            ArrayList games = new ArrayList();

            StreamReader sr = new StreamReader(file_name);
            if (sr != StreamReader.Null)
            {
                int number_of_hands = 0;
                while (!sr.EndOfStream)
                {


                    //czytamy linijke i ja wypisujemy
                    string line = sr.ReadLine();
                    //Console.WriteLine(line);

                    //rozdzielamy linijki na poszzczególne słowa
                    string[] tablica;
                    tablica = line.Split();

                    //jeżeli linijka zaczyna się od słowa Game, to zaczynamy parsowanie pojedynczej ręki
                    if (tablica[0] == "#Game")
                    {
                        
                        float pool = 0, rake = 0;
                        float big_bet, small_bet, small_blind;
                        long game_number, table_number;
                        DateTime date;
                        int dealer;
                        int number_of_players;
                        ArrayList game_players = new ArrayList();
                        ArrayList game_actions = new ArrayList();
                        Card flop_card_1 = null, flop_card_2 = null, flop_card_3 = null, turn_card = null, river_card = null;

                        number_of_hands++;
                        game_number = Convert.ToInt64(tablica[3]);
                        Console.WriteLine("reka " + number_of_hands + " " + game_number);

                        line = sr.ReadLine();
                        tablica = line.Split();

                        //Sprawdzamy, czy historia reki jest zapisana w pliku, czy nie wystapił komunikat:
                        //"Connection Lost due to some reason"
                        if (tablica[0] == "Connection")
                        {
                            number_of_hands--;
                            Console.WriteLine("reka stracona -------------------------");
                        }
                        else if (tablica[0] == "Table" && tablica[1] == "Closed")
                        {
                            continue;
                        }
                        else
                        {
                            line = sr.ReadLine();
                            tablica = line.Split();
                            string blindy = tablica[0];
                            string[] tab_blindy = blindy.Split('/');

                            //parsujemy wielkosc blindów
                            small_bet = (float)Convert.ToDouble(tab_blindy[0].Substring(1).Replace('.', ','));
                            big_bet = (float)Convert.ToDouble(tab_blindy[1].Substring(1).Replace('.', ','));

                            //parsujemy date i godzine
                            int year = Convert.ToInt16(tablica[10]);
                            int day = Convert.ToInt16(tablica[7].Substring(0, 2));
                            string month_str = tablica[6];
                            int month = getMonth(month_str);
                            int hour = Convert.ToInt16(tablica[8].Substring(0, 2));
                            int minute = Convert.ToInt16(tablica[8].Substring(3, 2));
                            int seconds = Convert.ToInt16(tablica[8].Substring(6, 2));
                            date = new DateTime(year, month, day, hour, minute, seconds);
                            //Console.WriteLine("{0:F}", date);

                            //parsujemy numer stołu
                            line = sr.ReadLine();
                            tablica = line.Split();
                            if (tablica[1] == "Speed")
                            {
                                table_number = Convert.ToInt64(tablica[2].Substring(1, tablica[2].Length - 1));
                            }
                            else
                            {
                                table_number = Convert.ToInt64(tablica[3]);
                            }
                            //Console.WriteLine(table_number);

                            //parsujemy numer siedzenia przy którym jest dealer button
                            line = sr.ReadLine();
                            tablica = line.Split();
                            dealer = Convert.ToInt16(tablica[1]);
                            //Console.WriteLine(dealer);

                            //parsujemy liczbe graczy
                            line = sr.ReadLine();
                            tablica = line.Split();
                            number_of_players = Convert.ToInt16(tablica[5]);
                            //Console.WriteLine(number_of_players);

                            game_players.Clear();

                            //parsujemy graczy, którzy siedzą przy stole
                            for (int k = 1; k <= number_of_players; k++)
                            {
                                line = sr.ReadLine();
                                tablica = line.Split();
                                int seat_number;
                                if (tablica[1].Length == 2)
                                {
                                    seat_number = Convert.ToInt16(tablica[1].Substring(0, 1));
                                }
                                else
                                {
                                    seat_number = Convert.ToInt16(tablica[1].Substring(0, 2));
                                }
                                string nickname = tablica[2];
                                float amount = (float)Convert.ToDouble(tablica[4].Substring(1).Replace('.', ','));

                                game_players.Add(new GamePlayer(seat_number, nickname, amount, game_number));
                                //Console.WriteLine(game_number + " " + seat_number + " " + nickname + " " + amount + "$");
                            }

                            //parsujemy kto wrzuca blindy
                            line = sr.ReadLine();
                            tablica = line.Split();
                            while (tablica[1] != "Dealing")
                            {
                                string name = tablica[0];
                                string blind = tablica[2];
                                if (blind == "sitting")
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == name)
                                        {
                                            player.setSO(true);
                                        }
                                    }

                                }
                                else if (blind == "left" || blind == "joined"){
                                    line = sr.ReadLine();
                                    tablica = line.Split();
                                    continue;
                                }
                                else if (tablica[5] == "dead")
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == name)
                                        {
                                            player.setBB(true);
                                            player.setSB(true);
                                            player.setDB(true);
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == name)
                                        {
                                            if (blind == "small")
                                            {
                                                player.setSB(true);
                                                Console.WriteLine(tablica[4]);
                                                small_blind = (float)Convert.ToDouble(tablica[4].Substring(2).Replace('.', ','));
                                                break;
                                            }
                                            else
                                            {
                                                player.setBB(true);
                                                break;
                                            }
                                        }
                                        else
                                            continue;
                                    }
                                }

                                line = sr.ReadLine();
                                tablica = line.Split();
                            }

                            //Dealt to me :)
                            line = sr.ReadLine();
                            tablica = line.Split();

                            string my_nick = tablica[2];
                            Console.WriteLine(my_nick);
                            foreach (GamePlayer player in game_players)
                            {
                                if (player.getNickname() == my_nick)
                                {
                                    player.setCard_1(new Card(tablica[5]));
                                    player.setCard_2(new Card(tablica[6]));
                                }
                            }

                            //akcja przed flopem
                            int lp = 0;
                            line = sr.ReadLine();
                            tablica = line.Split();
                            Console.WriteLine("-------------------------------" + tablica[1]);

                            //tutaj sprawdzamy czy ktos pokazal karty czy nie
                            //i po tej petli bedziemy parsowac wysokosc wygranej
                            string round = "preflop";
                            bool flag_open = false;
                            while (tablica[1] != "does" && tablica[1] != "doesn't" && tablica[1] != "shows")
                            {
                                if (tablica[1] == "calls")
                                {
                                    flag_open = true;
                                }
                                if (tablica[1] == "folds" || tablica[1] == "checks")
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == tablica[0])
                                        {
                                            game_actions.Add(new Action(game_number, lp++, round, player.getSeatNr(), tablica[1], 0, player.getNickname()));
                                        }
                                    }
                                }
                                else if (tablica[1] == "raises" && flag_open == false)
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == tablica[0])
                                        {
                                            float amount = (float)Convert.ToDouble(tablica[2].Substring(2).Replace('.', ','));
                                            game_actions.Add(new Action(game_number, lp++, round, player.getSeatNr(), "bets", amount, player.getNickname()));
                                            player.setWon(player.getWon() - amount);
                                            pool += amount;
                                        }
                                    }
                                }
                                else if (tablica[1] == "calls" || tablica[1] == "bets" || tablica[1] == "raises")
                                {
                                    foreach (GamePlayer player in game_players)
                                    {
                                        if (player.getNickname() == tablica[0])
                                        {
                                            float amount = (float)Convert.ToDouble(tablica[2].Substring(2).Replace('.', ','));
                                            game_actions.Add(new Action(game_number, lp++, round, player.getSeatNr(), tablica[1], amount, player.getNickname()));
                                            player.setWon(player.getWon() - amount);
                                            pool += amount;
                                        }
                                    }
                                }
                                //parsujemy karty wspolne i spawdzamy, która jest runda
                                else if (tablica[1] == "Dealing" && tablica[2] == "Flop")
                                {
                                    flop_card_1 = new Card(tablica[5].Substring(0, 2));
                                    flop_card_2 = new Card(tablica[6].Substring(0, 2));
                                    flop_card_3 = new Card(tablica[7]);
                                    round = "flop";
                                }
                                else if (tablica[1] == "Dealing" && tablica[2] == "Turn")
                                {
                                    turn_card = new Card(tablica[5]);
                                    round = "turn";
                                }
                                else if (tablica[1] == "Dealing" && tablica[2] == "River")
                                {
                                    river_card = new Card(tablica[5]);
                                    round = "river";
                                }
                                //else{
                                //  line = sr.ReadLine();
                                //  tablica = line.Split();
                                //}                 
                                line = sr.ReadLine();
                                tablica = line.Split();
                                //Console.WriteLine(line);
                            }

                            //parsujemy pokazane lub niepokazane karty przeciwnika
                            while (tablica[1] != "wins")
                            {
                                switch (tablica[1])
                                {
                                    case "doesn't":
                                        foreach (GamePlayer player in game_players)
                                        {
                                            if (player.getNickname() == tablica[0])
                                            {
                                                player.setCard_1(new Card(tablica[4].Substring(0, 2)));
                                                player.setCard_2(new Card(tablica[5]));
                                            }
                                        }
                                        break;
                                    case "shows":
                                        foreach (GamePlayer player in game_players)
                                        {
                                            if (player.getNickname() == tablica[0])
                                            {
                                                player.setCard_1(new Card(tablica[3].Substring(0, 2)));
                                                player.setCard_2(new Card(tablica[4]));
                                            }
                                        }
                                        break;
                                    default:
                                        break;
                                }
                                line = sr.ReadLine();
                                tablica = line.Split();
                            }
                            float wins_sum = 0;
                            while (tablica[1] == "wins")
                            {
                                foreach (GamePlayer player in game_players)
                                {
                                    if (player.getNickname() == tablica[0])
                                    {
                                        float w = (float)Convert.ToDouble(tablica[2].Substring(1).Replace('.', ','));
                                        player.setWon(w);
                                        wins_sum += w;

                                    }
                                }
                                line = sr.ReadLine();
                                tablica = line.Split();
                                if (tablica.Length == 1)
                                    break;
                            }
                            rake = pool - wins_sum;

                            //tutaj bawimy sie w ustalenie pozycji na jakich siedza konkretni gracze
                            bool[] sits = new bool[10];
                            for (int k = 0; k <= 9; k++)
                                sits[k] = false;

                            foreach (GamePlayer gp in game_players)
                            {
                                sits[(gp.getSeatNr() - 1)] = true;
                            }

                            Position[] pos = new Position[10];
                            pos[dealer - 1] = Position.BU;
                            bool flag = false;
                            
                            int count;
                            if (dealer == 1)
                                count = 9;
                            else
                                count = dealer - 2;
                            int actual_pos = (int)Position.BU;
                            while (flag == false)
                            {
                                if (sits[count] == true)
                                {
                                    if (actual_pos == 9)
                                        actual_pos = 0;
                                    else
                                        actual_pos++;

                                    pos[count] = (Position)actual_pos;
                                }

                                if (count == 0)
                                    count = 9;
                                else
                                    count--;
                                if (count == dealer - 1)
                                    flag = true;
                            }
                            //trzeba jeszcze przypisać BB i SB ponieważ pozycje liczymy od końca
                            if (dealer == 10)
                                count = 0;
                            else
                                count = dealer;
                            while (sits[count] == false)
                            {
                                if (count == 9)
                                    count = 0;
                                else count++;
                            }
                            pos[count] = Position.SB;
                            if (count == 9)
                                count = 0;
                            else count++;
                            while (sits[count] == false)
                            {
                                if (count == 9)
                                    count = 0;
                                else count++;
                            }
                            pos[count] = Position.BB;

                            //mamy policzone pozycje wiec dodajemy je do game_players
                            foreach (GamePlayer gp in game_players)
                            {
                                gp.setPosition(pos[gp.getSeatNr() - 1]);
                            }
                            

                            games.Add(new Hand(game_number, table_number, date, flop_card_1, flop_card_2, flop_card_3, turn_card, river_card,
                                                dealer, rake, number_of_players, big_bet, small_bet, pool, game_players, game_actions));
                        }
                        
                    }



                    /* for (int k = 0; k <= tablica.Length - 1; k++)
                     {
                       //  Console.WriteLine(k);
                         Console.WriteLine(k + " " + tablica[k]);
                     }*/
                }
            }
            else
            {
                Console.WriteLine("no");
            }


            sr.Close();
            return games;
        }
    }
}
